﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using Cleverscape.UTorrentClient.WebClient.ServiceDefinition;
using System.ComponentModel;
using System.Windows.Threading;
using GalaSoft.MvvmLight.Threading;

namespace Cleverscape.UTorrentClient.WebClient
{
    /// <summary>
    /// Represents a collection of Feeds
    /// </summary>
    public class FeedCollection : IList<Feed>, INotifyCollectionChanged, INotifyPropertyChanged
    {

        private List<Feed> _FeedCollectionInternal;

        internal UTorrentWebClient ParentClient { get; private set; }

        internal FeedCollection(UTorrentWebClient ParentClient)
        {
            this.ParentClient = ParentClient;
            _FeedCollectionInternal = new List<Feed>();
        }

        public FeedCollection()
        {
            _FeedCollectionInternal = new List<Feed>();
            for (int i = 0; i < 5; i++)
            {
                Feed f = new Feed();
                _FeedCollectionInternal.Add(f);
            }
        }

        #region Internal Methods

        internal void Parse(FeedsList FeedsToParse, bool IsFresh)
        {
            List<int> ListOfIdents = new List<int>();
            foreach (object[] FeedArray in FeedsToParse)
            {
                if (FeedArray.Length == 0)
                {
                    throw new FormatException("The array of Feed data was not in the expected format.");
                }
                ListOfIdents.Add(Convert.ToInt32(FeedArray[0]));
                Feed NewFeed = GetByIdent(Convert.ToInt32(FeedArray[0]));
                if (NewFeed == null)
                {
                    NewFeed = new Feed(FeedArray, this);
                    _FeedCollectionInternal.Add(NewFeed);
                    if (!IsFresh)
                    {
                        //ParentClient.CallEvent(UTorrentWebClient.EventType.Added, NewFeed);
                    }
                    CallCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, NewFeed, this.Count-1));
                }
                else
                {
                    NewFeed.UpdateValuesFromStringArray(FeedArray);

                }
            }
            IEnumerable<Feed> RemovedFeeds = RemoveWhereIdentIsNotInList(ListOfIdents);
            //foreach (Feed RemovedFeed in RemovedFeeds)
            //{
                
            //}
        }

        internal void Parse(RemovedFeedsList RemovedFeedsToParse, ChangedFeedsList ChangedFeedsToParse)
        {
            if (RemovedFeedsToParse == null || ChangedFeedsToParse == null)
            {
                return;
            }
            else
            {
                List<Feed> RemovedFeeds = new List<Feed>();
                foreach (object Feed in RemovedFeedsToParse)
                {
                    
                    RemovedFeeds.Clear();
                    RemovedFeeds.AddRange(RemoveByIdent(Convert.ToInt32(Feed)));
                    //foreach (Feed RemovedFeed in RemovedFeeds)
                    //{
                        
                    //}
                }
                foreach (object[] FeedArray in ChangedFeedsToParse)
                {
                    if (FeedArray.Length == 0)
                    {
                        throw new FormatException("The array of Feed data was not in the expected format.");
                    }
                    Feed NewFeed = GetByIdent(Convert.ToInt32(FeedArray[0]));
                    if (NewFeed == null)
                    {
                        NewFeed = new Feed(FeedArray, this);
                        _FeedCollectionInternal.Add(NewFeed);
                        //ParentClient.CallEvent(UTorrentWebClient.EventType.Added, NewFeed);
                        CallCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, NewFeed, this.Count-1));
                    }
                    else
                    {
                        NewFeed.UpdateValuesFromStringArray(FeedArray);
                    }
                }
            }
        }

        private IEnumerable<Feed> RemoveByIdent(int Ident)
        {
            List<Feed> FeedsToRemove = new List<Feed>();
            foreach (Feed CurrentFeed in _FeedCollectionInternal)
            {
                if (CurrentFeed.Ident == Ident)
                {
                    FeedsToRemove.Add(CurrentFeed);
                }
            }
            foreach (Feed FeedToRemove in FeedsToRemove)
            {
                int idx = _FeedCollectionInternal.IndexOf(FeedToRemove);
                _FeedCollectionInternal.Remove(FeedToRemove);
                CallCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, FeedToRemove, idx));
            }
            return FeedsToRemove;
        }

        private IEnumerable<Feed> RemoveWhereIdentIsNotInList(IEnumerable<int> ListOfIdents)
        {
            List<Feed> FeedsToRemove = new List<Feed>();
            foreach (Feed CurrentFeed in _FeedCollectionInternal)
            {
                if (!ListOfIdents.Contains(CurrentFeed.Ident))
                {
                    FeedsToRemove.Add(CurrentFeed);
                }
            }
            foreach (Feed FeedToRemove in FeedsToRemove)
            {
                int idx = _FeedCollectionInternal.IndexOf(FeedToRemove);
                _FeedCollectionInternal.Remove(FeedToRemove);
                CallCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, FeedToRemove, idx));
            }
            return FeedsToRemove;
        }


        private void CallCollectionChanged(NotifyCollectionChangedEventArgs EventArgs)
        {
            DispatcherHelper.UIDispatcher.BeginInvoke(() =>
            {
                if (CollectionChanged != null)
                {
                    if (ParentClient.Dispatcher == null || ParentClient.Dispatcher.CheckAccess())
                    {
                        CollectionChanged(this, EventArgs);
                    }
                    else
                    {
                        ParentClient.Dispatcher.BeginInvoke(new CallCollectionChangedAsyncCallback(CallCollectionChangedAsync), new object[] { EventArgs });
                    }
                }
            });
        }

        private void CallCollectionChangedAsync(NotifyCollectionChangedEventArgs EventArgs)
        {
            CollectionChanged(this, EventArgs);
        }

        private delegate void CallCollectionChangedAsyncCallback(NotifyCollectionChangedEventArgs EventArgs);

        internal void AddFeed(Feed FeedToAdd)
        {
            _FeedCollectionInternal.Add(FeedToAdd);
            this.ParentClient.FeedUpdateAdd(FeedToAdd);
        }

        #endregion

        #region Private Methods

        

        

        #endregion

        #region Public Methods

        public bool Contains(int Ident)
        {
            foreach (Feed CurrentFeed in _FeedCollectionInternal)
            {
                if (CurrentFeed.Ident == Ident)
                {
                    return true;
                }
            }
            return false;
        }

        public Feed GetByIdent(int Ident)
        {
            foreach (Feed CurrentFeed in _FeedCollectionInternal)
            {
                if (CurrentFeed.Ident == Ident)
                {
                    return CurrentFeed;
                }
            }
            return null;
        }

        

        public void Insert(int index, Feed item)
        {
        }

        public void Clear()
        {
        }

        public void Add(Feed item)
        {
            AddFeed(item);
        }

        public int IndexOf(Feed item)
        {
            return _FeedCollectionInternal.IndexOf(item);
        }

        public void RemoveAt(int index)
        {
            throw new NotImplementedException();
        }

        public Feed this[int index]
        {
            get
            {
                return _FeedCollectionInternal[index];
            }
            set
            {
            }
        }

        public bool Contains(Feed item)
        {
            return (GetByIdent(item.Ident) != null);
        }

        public void CopyTo(Feed[] array, int arrayIndex)
        {
            _FeedCollectionInternal.CopyTo(array, arrayIndex);
        }

        public int Count
        {
            get { return _FeedCollectionInternal.Count; }
        }

        public bool IsReadOnly
        {
            get { return true; }
        }

        public bool Remove(Feed item)
        {
            if (GetByIdent(item.Ident) != null)
            {
                item.Remove();
                _FeedCollectionInternal.Remove(item);
                return true;
            }
            return false;
        }

        public IEnumerator<Feed> GetEnumerator()
        {
            return _FeedCollectionInternal.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return _FeedCollectionInternal.GetEnumerator();
        }

        #endregion

        #region Public Events (Interface Implementation)

        public event NotifyCollectionChangedEventHandler CollectionChanged;

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(string PropertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
            }
        }

        #endregion

    }
}
